package ru.amse.jsynchro.GUI;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;

import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import javax.swing.border.TitledBorder;

import ru.amse.jsynchro.logging.ILogger;
import ru.amse.jsynchro.logging.LogFactory;
import ru.amse.jsynchro.net.Client;

@SuppressWarnings("serial")
public class ClientFrame extends JFrame implements IStatusObserver {
    private JLabel statusBar;
    private JTextField folderField;
    private JTextField portField;
    private JTextField hostField; 
    private JTextField nameField;
    private JPasswordField passwordField;
    private boolean working = false;
    
    private ILogger logger = LogFactory.getClientLogger(true, LogFactory.CONSOLE_LOG);
    
    private Client client;
    
    private Properties properties;
    private final String FOLDER_PROPERTY = "selected_folder";
    private final String PORT_PROPERTY = "port";
    private final String HOST_PROPERTY = "host";
    private final String NAME_PROPERTY = "name";
    private final String PASSWORD_PROPERTY = "password";
    private final String SETTINGS_FILE = "client.config";
    
    public ClientFrame() {
        setSize(290, 315);
        setTitle("JSynchro");
        
        if (!loadSettings()) {
            logger.info("client config file problems");
        }
        
        JPanel mainPanel = new JPanel();
        mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
        mainPanel.setBorder(BorderFactory.createEmptyBorder(12, 12, 12, 12));
        
        statusBar = new JLabel("Ready");
        getContentPane().add(statusBar, BorderLayout.SOUTH);
        
        mainPanel.add(createFolderPanel());
        mainPanel.add(Box.createVerticalStrut(12));
        mainPanel.add(createAccountPanel());
        mainPanel.add(Box.createVerticalStrut(12));
        mainPanel.add(createConnectionPanel());
        mainPanel.add(Box.createVerticalStrut(12));
        mainPanel.add(createButtonsPanel());
        
        getContentPane().add(mainPanel);
        
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                if (working) {
                    client.off();
                }
                saveSettings();
                System.exit(0);
            }
        });
        
        setResizable(false);
        setVisible(true);
    }
    
    public static void main(String[] args) {
        new ClientFrame();
    }
    
    private boolean loadSettings() {
        properties = new Properties();
        try {
            properties.load(new FileReader(SETTINGS_FILE));
        } catch (FileNotFoundException e) {
            properties.setProperty(FOLDER_PROPERTY, "");
            try {
                properties.store(new FileWriter(SETTINGS_FILE), null);
            } catch (IOException e1) {
                return false;
            }
            return false;
        } catch (IOException e) {
            return false;
        }
        return true;
    }
    
    private void saveSettings() {
        properties.setProperty(FOLDER_PROPERTY, folderField.getText());
        properties.setProperty(HOST_PROPERTY, hostField.getText());
        properties.setProperty(PORT_PROPERTY, portField.getText());
        properties.setProperty(NAME_PROPERTY, nameField.getText());
        properties.setProperty(PASSWORD_PROPERTY, String.copyValueOf(passwordField.getPassword()));
        try {
            properties.store(new FileWriter(SETTINGS_FILE), null);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    private JPanel createFolderPanel() {
            JPanel panel = new JPanel();
            panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
    //        panel.add(Box.createHorizontalGlue());
            panel.add(new JLabel("Select Folder:"));
    //        panel.add(Box.createHorizontalStrut(5));
            panel.add(Box.createHorizontalStrut(12));
            
            JFileChooser folderChooser = new JFileChooser();
            folderChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
            String curFolder = properties.getProperty(FOLDER_PROPERTY);
            folderChooser.setCurrentDirectory(new File(curFolder));
            folderField = new JTextField(curFolder, 30);
            fixTextFieldSize(folderField);
            fixTextFieldSize(folderField);
            panel.add(folderField);
            
    //        panel.add(Box.createHorizontalGlue());
            JButton selectFolderBtn = new JButton(new ChooserAction(folderChooser, folderField));
            panel.add(selectFolderBtn);
            panel.add(Box.createHorizontalGlue());
            panel.setAlignmentX(JComponent.LEFT_ALIGNMENT);
            panel.setBorder(new TitledBorder("Current Folder"));
            return panel;
        }

    private JPanel createAccountPanel() {
        JPanel panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
        
        JPanel namePanel = new JPanel();
        namePanel.setLayout(new BoxLayout(namePanel, BoxLayout.X_AXIS));
        JLabel nameLabel = new JLabel("Name:");
        namePanel.add(nameLabel);
        namePanel.add(Box.createHorizontalStrut(12));
        nameField = new JTextField(properties.getProperty(NAME_PROPERTY));
        namePanel.add(nameField);
        panel.add(namePanel);
        
        JPanel passwordPanel = new JPanel();
        passwordPanel.setLayout(new BoxLayout(passwordPanel, BoxLayout.X_AXIS));
        JLabel passwordLabel = new JLabel("Password:");
        passwordPanel.add(passwordLabel);
        passwordPanel.add(Box.createHorizontalStrut(12));
        passwordField = new JPasswordField(properties.getProperty(PASSWORD_PROPERTY));
        passwordPanel.add(passwordField);
        
        
        panel.add(passwordPanel);
        setGroupAlignmentX(JComponent.LEFT_ALIGNMENT, panel, namePanel, passwordPanel);
        setGroupAlignmentY(JComponent.CENTER_ALIGNMENT, 
                passwordField, nameField, passwordLabel, nameLabel);
        setSameSize(passwordLabel, nameLabel);
        fixTextFieldSize(nameField);
        fixTextFieldSize(passwordField);
        panel.setBorder(new TitledBorder("Account"));
        return panel;
    }
    
    private JPanel createConnectionPanel() {
        JPanel main = new JPanel();
        main.setLayout(new BoxLayout(main, BoxLayout.Y_AXIS));
        
        JPanel addrPanel = new JPanel();
        addrPanel.setLayout(new BoxLayout(addrPanel, BoxLayout.X_AXIS));
        
        JLabel hostLabel = new JLabel("Server:");
        addrPanel.add(hostLabel);
        addrPanel.add(Box.createHorizontalStrut(12));
        
        String host = "localhost";
        host = properties.getProperty(HOST_PROPERTY);
        hostField = new JTextField(host, 15);
        addrPanel.add(hostField);
        main.add(addrPanel);
        
        JPanel portPanel = new JPanel();
        portPanel.setLayout(new BoxLayout(portPanel, BoxLayout.X_AXIS));
        JLabel portLabel = new JLabel("Port:");
        portPanel.add(portLabel);
        portPanel.add(Box.createHorizontalStrut(12));
        
        String port = "12345";
        port = properties.getProperty(PORT_PROPERTY);
        portField = new JTextField(port, 7);
        portPanel.add(portField);
        main.add(portPanel);
        
        setGroupAlignmentX(JComponent.LEFT_ALIGNMENT, main, addrPanel, portPanel);
        setGroupAlignmentY(JComponent.CENTER_ALIGNMENT, 
                hostField, portField, portLabel, hostLabel);
        setSameSize(portLabel, hostLabel);
        fixTextFieldSize(hostField);
        fixTextFieldSize(portField);
        
        main.setBorder(new TitledBorder("Connect to"));
        return main;
    }
    
    private JPanel createButtonsPanel() {
        JPanel panel = new JPanel();
        panel.setLayout(new GridLayout(1,2,5,0));
        JButton startBtn = new JButton(new StartAction(this));
        panel.add(startBtn);
        
        JButton updateBtn = new JButton(new UpdateAction(this));
        panel.add(updateBtn);
        
        JButton commitBtn = new JButton(new UploadAction(this));
        panel.add(commitBtn);
        setRecommendedMargin(startBtn, updateBtn, commitBtn);
        panel.setAlignmentX(JComponent.LEFT_ALIGNMENT);
        return panel;
    }
    
    private void setRecommendedMargin(JButton... btns) {
        for (JButton b: btns) {
            Insets margin = b.getMargin();
            margin.left = 12;
            margin.right = 12;
            b.setMargin(margin);
        }
    }

    private void setGroupAlignmentY(float al, JComponent... cs) {
        for (JComponent c: cs) {
            c.setAlignmentY(al);
        }
    }
    
    private void setSameSize(JComponent... cs) {
        int maxPos = 0;
        int maxSize = 0;
        int i = 0;
        for (JComponent c: cs) {
            if (c.getPreferredSize().width > maxSize) {
                maxSize = c.getPreferredSize().width;
                maxPos = i;
            }
            i++;
        }
        Dimension maxDimension = cs[maxPos].getPreferredSize();
        for (JComponent c: cs) {
            c.setPreferredSize(maxDimension);
            c.setMaximumSize(maxDimension);
            c.setMinimumSize(maxDimension);
        }
    }
    
    private void fixTextFieldSize(JTextField field) {
        Dimension size = field.getPreferredSize();
        size.width = field.getMaximumSize().width;
        field.setMaximumSize(size);
    }
    
    private void setGroupAlignmentX(float al, JComponent... cs) {
        for (JComponent c: cs) {
            c.setAlignmentX(al);
        }
    }
    
    public void setState(String status) {
        statusBar.setText(status);
    }

    @SuppressWarnings("serial")
    private class ChooserAction extends AbstractAction {
        private JFileChooser chooser;
        private JTextField folderFielld;
        public ChooserAction(JFileChooser chooser, JTextField folderField) {
            super();
            putValue(AbstractAction.NAME, "Open");
            this.chooser = chooser;
            this.folderFielld = folderField;
        }
        public void actionPerformed(ActionEvent e) {
            int res = chooser.showOpenDialog(null);
            if (res == JFileChooser.APPROVE_OPTION) {
                folderFielld.setText(chooser.getSelectedFile().getPath());
            }
        }
    }
    
    @SuppressWarnings("serial")
    private class StartAction extends AbstractAction {
        private IStatusObserver stObserver;
        public StartAction(IStatusObserver stObserver) {
            super();
            putValue(AbstractAction.NAME, "Auto");
            this.stObserver = stObserver;
        }
        public void actionPerformed(ActionEvent e) {
            if (!working) {
                putValue(AbstractAction.NAME, "Cancel");
                client = new Client(folderField.getText(), 
                        nameField.getText(), passwordField.getPassword(), 
                        hostField.getText(), Integer.parseInt(portField.getText()),
                        logger, stObserver);
                client.setThreadType(Client.START);
                client.start();
                working = true;
            } else {
                putValue(AbstractAction.NAME, "Auto");
                working = false;
                client.off();
                statusBar.setText("Ready");
            }
        }
    }
    
    private class UpdateAction extends AbstractAction {
        private IStatusObserver stObserver;
        public UpdateAction(IStatusObserver stObserver) {
            super();
            putValue(AbstractAction.NAME, "Update");
            this.stObserver = stObserver;
        }
        public void actionPerformed(ActionEvent e) {
            if (working) {
                client.off();
                working = false;
            }
            setEnabled(false);
            client = new Client(folderField.getText(), 
                    nameField.getText(), passwordField.getPassword(), 
                    hostField.getText(), Integer.parseInt(portField.getText()),
                    logger, stObserver);
            client.setThreadType(Client.UPDATE);
            client.start();
            setEnabled(true);
            statusBar.setText("Ready");
        }
    }
    
    private class UploadAction extends AbstractAction {
        private IStatusObserver stObserver;
        public UploadAction(IStatusObserver stObserver) {
            super();
            putValue(AbstractAction.NAME, "Commit");
            this.stObserver = stObserver;
        }
        public void actionPerformed(ActionEvent e) {
            if (working) {
                client.off();
                working = false;
            }
            setEnabled(false);
            client = new Client(folderField.getText(), 
                    nameField.getText(), passwordField.getPassword(), 
                    hostField.getText(), Integer.parseInt(portField.getText()),
                    logger, stObserver);
            client.setThreadType(Client.UPLOAD);
            client.start();
            setEnabled(true);
            statusBar.setText("Ready");
        }
    }
}
